package com.wuyou.securitydemo.pwd;

import com.wuyou.sso.common.contant.AuthConstants;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * PasswordAuthenticationProcessingFilter
 *
 * @Date 2025/4/7 13:41
 * @Author 无忧
 */
@Slf4j
@Getter
@Setter
public class CustomizedPasswordAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    @Autowired
    private AuthenticationEventPublisher eventPublisher;

    @Autowired
    private AuthenticationEntryPoint authExceptionEntryPoint;


    public CustomizedPasswordAuthenticationProcessingFilter() {
        super(new AntPathRequestMatcher(AuthConstants.LOGIN_URI, "POST"));
    }

    @Nullable
    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter("password") != null ? request.getParameter("password") : "";
    }

    @Nullable
    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter("username") != null ? request.getParameter("username") : "";
    }

    @Nullable
    protected Long obtainTenantId(HttpServletRequest request) {
        return request.getParameter("tenantid") != null ? Long.valueOf(request.getParameter("tenantid")) : 0L;
    }

    @Nullable
    protected String obtainCompanyCode(HttpServletRequest request) {
        return request.getParameter("companyCode") != null ? request.getParameter("companyCode") : "";
    }

    @Nullable
    protected String obtainTenantName(HttpServletRequest request) {
        return request.getParameter("tenantName") != null ? request.getParameter("tenantName") : "";
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {


        CustomizedPasswordAuthenticationToken authenticationToken = new CustomizedPasswordAuthenticationToken(this.obtainUsername(request).trim(), this.obtainPassword(request));
        setDetails(request, authenticationToken);

        Authentication authResult = null;
        try {
            authResult = this.getAuthenticationManager().authenticate(authenticationToken);
            log.debug("Authentication success：{}", authResult);
            SecurityContextHolder.getContext().setAuthentication(authResult);
        } catch (Exception failed) {
            SecurityContextHolder.clearContext();
            log.debug("Authentication request failed：{}", failed);

            eventPublisher.publishAuthenticationFailure(
                    new BadCredentialsException(failed.getMessage(), failed),
                    new PreAuthenticatedAuthenticationToken("access-token", "N/A"));

            try {
                authExceptionEntryPoint.commence(
                        request, response, new UsernameNotFoundException(failed.getMessage(), failed));
            } catch (Exception e) {
                log.error("authenticationEntryPoint handle error:{}", failed);
            }
        }
        return authResult;
    }

    private void setDetails(HttpServletRequest request, CustomizedPasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }
}
